<template>
    <div class="page-index">
        <div class="dialog-wrap" v-if="showRecorder">
            <recorder :showRecorder.sync="showRecorder" @send="sendRecord"></recorder>
        </div>
        <div id="head-info">
            <span>{{`${roomName}(${members})`}}</span>
            <img id="avatar" :src="avatar" alt="avatar" @click="toUser" />
        </div>
        <div id="chatbox">
            <div class="bubble" v-for="(chat, index) in chats" :key="chat._id" :class="{'own': chat.from._id === id}">
                <span class="mes-time" v-if="checkTime(chat.time, index)">{{fmtTime(chat.time)}}</span>
                <message ref="message" :index="index" :chat="chat" @play="playVoice"></message>
            </div>
            <audio id="voice-player" src=""></audio>
        </div>
        <div id="edit-ctrl">
            <ul id="tools">
                <li v-for="tool in tools" :key="tool.name">
                    <icon :name="tool.name" scale="1.5" @click.native="clickTool(tool)"></icon>
                    <input v-if="tool.name === 'image'" :id="tool.name" type="file" accept="image/jpeg, image/png, image/gif" @change="selectImage" />
                </li>
            </ul>
            <div id="input-area" contenteditable="true" @paste="pasteImg" @keypress.enter.prevent="send()"></div>
        </div>
    </div>
</template>

<script>
import { mapState, mapActions, mapMutations } from 'vuex';
import recorder from '../components/Recorder.vue';
import message from '../components/Message.vue';

function setState(store) { }
function askPermission() {
    return new Promise(function (resolve, reject) {
        var permissionResult = Notification.requestPermission(function (result) {
            // 旧版本
            resolve(result);
        });
        if (permissionResult) {
            // 新版本
            permissionResult.then(resolve, reject);
        }
    })
        .then(function (permissionResult) {
            if (permissionResult !== 'granted') {
                // 用户未授权
            }
        });
}

export default {
    name: 'index',
    components: {
        recorder,
        message
    },
    metaInfo: {
        title: "JDT-Bros' chatting room ",
        meta: [
            { name: 'keywords', content: 'JDT,jxy,dmq,ty,chat' },
            { name: 'description', content: '汝可曾想念，吾不知为何。' }
        ]
    },
    data() {
        return {
            tools: [
                { name: "microphone" },
                { name: "image" }
            ],
            id: "",

            showRecorder: false,

            chats: [],
            avatar: "",
            roomName: "",
            roomId: ""
        }
    },
    computed: {
        ...mapState('chatStatus', {
            logged: state => state.logged,
            members: state => state.members
        })
    },
    async asyncData({ store, route }) {
        setState(store);
    },
    mounted() {
        this.fetchUser().then(data => {
            this.fetchChats(data.rooms[0]);
            this.wsGetMessage(data.rooms[0]);
        })
    },
    methods: {
        ...mapMutations('chatStatus', [
            'setMembers'
        ]),
        toBottom() {
            this.$nextTick(() => {
                let box = this.$el.querySelector("#chatbox");
                box.scrollTop = box.scrollHeight - box.offsetHeight;
            })
        },
        fmtTime(time) {
            let date = new Date(time);
            return date.Format("yyyy-MM-dd hh:mm:ss")
        },
        checkTime(time, index) {
            if (index === 0) return true;
            else {
                let dis = new Date(time).getTime() - new Date(this.chats[index - 1].time).getTime();
                if ((dis / 1000 / 60) > 3) return true;
                else return false
            }
        },
        fetchUser() {
            return new Promise((resolve, reject) => {
                this.axios.post("user/find", { id: localStorage.getItem("id") || "" }).then(res => {
                    if (res.data.ok) {
                        let obj = res.data.data;
                        this.avatar = obj.avatar;
                        localStorage.setItem("account", obj.account);
                        localStorage.setItem("avatar", obj.avatar);
                        localStorage.setItem("name", obj.name);
                        localStorage.setItem("id", obj._id);
                        this.id = obj._id;
                        resolve(obj);
                    } else reject(res)
                })
            })
        },
        fetchChats(roomId) {
            this.axios.post("room/enter", { roomId: roomId }).then(res => {
                this.setMembers(res.data.data.members.length);
                this.roomName = res.data.data.name;
                this.roomId = res.data.data._id;
                this.chats = res.data.data.chats;
                this.toBottom();
            })
        },
        wsGetMessage(roomId) {
            const ws = new WebSocket(`${this.wsUrl}chat/${roomId}`);
            ws.onopen = con => {
                let obj = {
                    account: localStorage.account,
                    token: localStorage.token
                };
                ws.send(JSON.stringify(obj));
                ws.onmessage = e => {
                    let newMes = JSON.parse(e.data).data;
                    this.chats.push(newMes);
                    this.$forceUpdate();
                    this.toBottom();
                    if (document.hidden) {
                        let body;
                        if (newMes.isImg) body = "[图片]";
                        else if (newMes.isVoice) body = "[语音]";
                        else body = newMes.inner;
                        let title = `${newMes.from.name}发来一条新信息！`,
                            options = {
                                body: body,
                                icon: newMes.from.avatar
                            }
                        askPermission().then(res => {
                            let notification = new Notification(title, options);
                        })
                    }
                }
            }
        },
        toUser() {
            this.$router.replace({ name: "user" });
        },
        clickTool(tool) {
            if (tool.name === "image") {
                document.querySelector("#image").click();
            } else if (tool.name = "microphone") {
                this.showRecorder = true;
                this.stopVoiceSpin();
            }
        },
        setFocuse(el) {
            let range = document.createRange();
            range.selectNodeContents(el);
            range.collapse(false);
            let sel = window.getSelection();
            //判断光标位置，如不需要可删除
            if (sel.anchorOffset != 0) {
                return;
            };
            sel.removeAllRanges();
            sel.addRange(range);
        },
        pasteImg(event) {
            if (event.clipboardData || event.originalEvent) {
                //某些chrome版本使用的是event.originalEvent
                let clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
                if (clipboardData.items) {
                    // for chrome
                    let items = clipboardData.items,
                        len = items.length,
                        blob = null,
                        text = null;
                    for (let i = 0; i < len; i++) {
                        if (items[i].type.indexOf("image") !== -1) {
                            blob = items[i].getAsFile();
                        }
                        if (items[i].type.indexOf("html") !== -1) {
                            event.preventDefault();

                            items[i].getAsString(dom => {
                                if (dom != null) {
                                    let tmp = document.createElement("span");
                                    tmp.innerHTML = dom;
                                    event.target.innerHTML += tmp.innerText;
                                    this.setFocuse(event.target);
                                }
                            });
                        }
                    }
                    if (blob !== null) {
                        this.uploadImg(blob)
                    }
                }
            }
        },

        selectImage(e) {
            for (let i = 0; i < e.target.files.length; i++) {
                this.uploadImg(e.target.files[i]);
            }
        },

        sendRecord(file) {
            this.send(file);
        },

        checkInfoType(ogg) {
            if (!ogg) {
                let area = document.querySelector("#input-area"),
                    imgs = area.querySelectorAll("img");
                if (imgs.length > 0) {
                    if (area.innerText === "") return { img: imgs, text: null };
                    else return { img: imgs, text: area.innerText };
                } else {
                    return { img: null, text: area.innerText };
                }
            } else {
                return {
                    img: null,
                    voice: ogg
                }
            }
        },

        uploadImg(file) {
            let src = new FormData();
            src.append("file", file);
            src.append("Content-Type", file.type);
            src.append("filename", file.name);

            this.axios.post("upload/img", src).then(res => {
                let img = document.createElement("img");
                img.src = res.data;
                document.getElementById("input-area").appendChild(img);
                this.send();
            }).catch(err => {
                console.log(err);
            })
        },

        send(file) {
            let innerText = document.querySelector("#input-area").innerText;
            let area = document.querySelector("#input-area");
            let inner = file ? this.checkInfoType(file) : this.checkInfoType();
            if (inner.img != null) {
                inner.img.forEach((v, i) => {
                    let con = {
                        content: v.getAttribute("src"),
                        isImg: true
                    };
                    this.mes(con);
                })
            } else if (inner.voice != null) {
                this.uploadRecord(inner.voice, res => {
                    let con = {
                        content: res,
                        isVoice: true
                    };
                    this.mes(con);
                })
            } else {
                if (inner.text != "") {
                    let con = {
                        content: inner.text
                    }
                    this.mes(con);
                }
            }
        },

        uploadRecord(file, cb) {
            let src = new FormData();
            src.append("file", file);
            src.append("Content-Type", file.type);
            src.append("filename", file.name);

            this.axios.post("upload/voice", src).then(res => {
                cb(res.data);
            }).catch(err => {
                console.log(err);
            })
        },

        mes(inner) {
            this.axios.post("chat/send", {
                inner: inner.content,
                isImg: inner.isImg || false,
                isVoice: inner.isVoice || false,
                userId: localStorage.id,
                roomId: this.roomId
            }).then(res => {
                document.getElementById("input-area").innerHTML = "";
            })
        },

        stopVoiceSpin() {
            let player = document.querySelector("#voice-player");
            let playingSpin = document.querySelector(".playing");
            if (playingSpin != null) playingSpin.classList.remove("playing");
            player.pause();
        },

        playVoice(src, el) {
            this.stopVoiceSpin();
            el.querySelector(".spinner").classList.add("playing");
            let player = document.querySelector("#voice-player");
            player.src = src;
            player.load();
            player.play();
            player.onended = () => {
                el.querySelector(".spinner").classList.remove("playing");
            }
        }
    }
};
</script>

<style>
.page-index {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	align-items: center;
}

.page-index * {
	box-sizing: border-box;
}

.page-index #head-info {
	width: 100%;
	height: 60px;
	padding: 15px 20px;
	background-color: #972624;
	color: #fff;
	font-size: 18px;
}

.page-index #head-info > span {
	display: inline-block;
	vertical-align: -webkit-baseline-middle;
}

.page-index #head-info #avatar {
	float: right;
	cursor: pointer;
	width: 32px;
}

.page-index #chatbox {
	width: 100%;
	padding: 15px 20px;
	height: calc(100% - 135px);
	overflow: auto;
}

.bubble {
	margin-bottom: 20px;
}

#edit-ctrl {
	width: 100%;
	padding: 5px 20px 15px 20px;
	border-top: 1px solid #eee;
}

#edit-ctrl ul {
	padding: 0;
	margin: 0;
	width: 100%;
	height: 28px;
	display: flex;
}

#edit-ctrl li {
	list-style: none;
	width: 30px;
	margin-right: 10px;
	color: #449ece;
	position: relative;
}

#edit-ctrl li svg {
	cursor: pointer;
}

#edit-ctrl li input {
	position: absolute;
	width: 30px;
	overflow: hidden;
	opacity: 0;
	cursor: pointer;
	left: 0;
	display: none;
}

#input-area {
	width: 100%;
	max-height: 80px;
	border: none;
	padding-top: 8px;
	overflow: auto;
	white-space: pre-wrap;
	word-break: break-all;
}

#input-area:focus {
	outline: 0;
}

#input-area img {
	max-height: 100%;
	margin-right: 5px;
}

.dialog-wrap {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	/* background-color: #0003; */
	z-index: 5000;
}

.dialog-wrap > div {
	width: 300px;
	height: 280px;
	position: absolute;
	left: 50%;
	top: 20%;
	transform: translateX(-50%);
	text-align: center;
	background-color: hsla(0, 0%, 93%, 0.96);
	color: #333;
	border-radius: 13px;
	padding: 40px;
}
</style>
